package com.wimcorp.magic.host;

import java.util.Set;

import com.wimcorp.magic.behaviour.Defender;
import com.wimcorp.magic.behaviour.DoesNotUnTapNextTurn;
import com.wimcorp.magic.behaviour.DoesNotUnTapOnUpkeep;
import com.wimcorp.magic.behaviour.Flying;
import com.wimcorp.magic.behaviour.Haste;
import com.wimcorp.magic.behaviour.Hexproof;
import com.wimcorp.magic.behaviour.Intimidate;
import com.wimcorp.magic.behaviour.Islandwalk;
import com.wimcorp.magic.behaviour.Morbid;
import com.wimcorp.magic.behaviour.Reach;
import com.wimcorp.magic.behaviour.SummoningSickness;
import com.wimcorp.magic.behaviour.Tapped;
import com.wimcorp.magic.behaviour.Unblockable;
import com.wimcorp.magic.behaviour.attack.DeathTouch;
import com.wimcorp.magic.behaviour.attack.DefaultAttack;
import com.wimcorp.magic.behaviour.attack.DoubleStrike;
import com.wimcorp.magic.behaviour.attack.FirstStrike;
import com.wimcorp.magic.behaviour.attack.LifeLink;
import com.wimcorp.magic.behaviour.attack.Trample;
import com.wimcorp.magic.board.CardAccessor;
import com.wimcorp.magic.cards.Artifact;
import com.wimcorp.magic.cards.Creature;
import com.wimcorp.magic.cards.Enchantment;
import com.wimcorp.magic.cards.Instant;
import com.wimcorp.magic.cards.Land;
import com.wimcorp.magic.cards.Permanent;
import com.wimcorp.magic.cards.Planeswalker;
import com.wimcorp.magic.cards.PlayingCard;
import com.wimcorp.magic.cards.Sorcery;
import com.wimcorp.magic.color.Color;
import com.wimcorp.magic.input.BehaviorInput;
import com.wimcorp.magic.input.Type;
import com.wimcorp.magic.players.Player;

public class CardInputValidator {
	private Player player;
	private Set<String> types;
	private Set<String> locations;
	private Set<String> behaviors;
	private long identifier;

	public CardInputValidator(Player player, Set<String> types, Set<String> locations, Set<String> behaviors,
			long identifier) {
		this.player = player;
		this.types = types;
		this.locations = locations;
		this.behaviors = behaviors;
		this.identifier = identifier;
	}

	public boolean isValid() {
		long result = identifier;
		for (String location : locations) {
			CardAccessor cardAccessor = CardAccessor.getCardAccessor(player, location);
			if (cardAccessor != null) {
				result = validateType(cardAccessor, types, identifier);
				if (result > 0) {
					result = validateBehavior(cardAccessor, behaviors, identifier);
					if (result != -1) {
						return true;
					}
				}
			}

		}
		//Check if this creature is controlled by opponent.
		for (String location : locations) {
			CardAccessor cardAccessor = CardAccessor.getCardAccessor(player.getOpponent(), location);
			PlayingCard card = cardAccessor.getCard(identifier);
			if (card != null && card.getPlayer() != null &&  player.getName().equals(card.getPlayer().getName())) {
				if (cardAccessor != null) {
					result = validateType(cardAccessor, types, identifier);
					if (result > 0) {
						result = validateBehavior(cardAccessor, behaviors, identifier);
						if (result != -1) {
							return true;
						}
					}
				}
			}
		}
		return false;
	}

	private long validateType(CardAccessor cardAccessor, Set<String> types, long identifier) {
		int passCounter = 0;
		for (String type : types) {
			if (type.contains("_OR_")) {
				String[] split = type.split("_OR_");
				for (String t : split) {
					if (validateTarget(cardAccessor, t, identifier) != -1) {
						passCounter++;
					}
				}
			} else {
				if (validateTarget(cardAccessor, type, identifier) != -1) {
					passCounter++;
				}
			}
		}
		if (passCounter == types.size()) {
			return identifier;
		}
		return -1;
	}

	private long validateTarget(CardAccessor cardAccessor, String type, long identifier) {
		PlayingCard card = cardAccessor.getCard(identifier);
		if (card != null) {
			switch (Type.valueOf(type)) {
			case ARTIFACT:
				if (card instanceof Artifact) {
					return identifier;
				}
				break;
			case CARD:
				if (card instanceof PlayingCard) {
					return identifier;
				}
				break;
			case CREATURE:
				if (card instanceof Creature) {
					return identifier;
				}
				break;
			case ENCHANTMENT:
				if (card instanceof Enchantment) {
					return identifier;
				}
				break;
			case INSTANT:
				if (card instanceof Instant) {
					return identifier;
				}
				break;
			case LAND:
				if (card instanceof Land) {
					return identifier;
				}
				break;
			case NON_ARTIFACT:
				if (!(card instanceof Artifact)) {
					return identifier;
				}
				break;
			case NON_CREATURE:
				if (!(card instanceof Creature)) {
					return identifier;
				}
				break;
			case NON_ENCHANTMENT:
				if (!(card instanceof Enchantment)) {
					return identifier;
				}
				break;
			case NON_INSTANT:
				if (!(card instanceof Instant)) {
					return identifier;
				}
				break;
			case NON_LAND:
				if (!(card instanceof Land)) {
					return identifier;
				}
				break;
			case NON_PERMANENT:
				if (!(card instanceof Permanent)) {
					return identifier;
				}
				break;
			case PERMANENT:
				if (card instanceof Permanent) {
					return identifier;
				}
				break;
			case PLANESWALKER:
				if (card instanceof Planeswalker) {
					return identifier;
				}
				break;
			case SORCERY:
				if (card instanceof Sorcery) {
					return identifier;
				}
				break;
			case NON_BLUE:
				if (!card.getColors().contains(Color.BLUE)) {
					return identifier;
				}
				break;
			case NON_BLACK:
				if (!card.getColors().contains(Color.BLACK)) {
					return identifier;
				}
				break;
			case NON_GREEN:
				if (!card.getColors().contains(Color.GREEN)) {
					return identifier;
				}
				break;
			case NON_RED:
				if (!card.getColors().contains(Color.RED)) {
					return identifier;
				}
				break;
			case NON_WHITE:
				if (!card.getColors().contains(Color.WHITE)) {
					return identifier;
				}
				break;
			case BLUE:
				if (card.getColors().contains(Color.BLUE)) {
					return identifier;
				}
				break;
			case BLACK:
				if (card.getColors().contains(Color.BLACK)) {
					return identifier;
				}
				break;
			case GREEN:
				if (card.getColors().contains(Color.GREEN)) {
					return identifier;
				}
				break;
			case RED:
				if (card.getColors().contains(Color.RED)) {
					return identifier;
				}
				break;
			case WHITE:
				if (card.getColors().contains(Color.WHITE)) {
					return identifier;
				}
				break;
			}
		}
		return -1;
	}

	private long validateBehavior(CardAccessor cardAccessor, Set<String> behaviors, long identifier) {
		int passCounter = 0;
		for (String behavior : behaviors) {
			if (validateBehavior(cardAccessor, behavior, identifier) != -1) {
				passCounter++;
			}
		}
		if (passCounter == behaviors.size()) {
			return identifier;
		}
		return -1;
	}

	private long validateBehavior(CardAccessor cardAccessor, String behaviors, long identifier) {
		PlayingCard card = cardAccessor.getCard(identifier);
		if (card != null) {
			switch (BehaviorInput.valueOf(behaviors)) {
			case DEATH_TOUCH:
				if (card.hasBehaviour(DeathTouch.instance())) {
					return identifier;
				}
				break;
			case DEFAULT_ATTACK:
				if (card.hasBehaviour(DefaultAttack.instance())) {
					return identifier;
				}
				break;
			case DEFENDER:
				if (card.hasBehaviour(Defender.instance())) {
					return identifier;
				}
				break;
			case DOES_NOT_UN_TAP_NEXT_TURN:
				if (card.hasBehaviour(DoesNotUnTapNextTurn.instance())) {
					return identifier;
				}
				break;
			case DOES_NOT_UN_TAP_ON_UPKEEP:
				if (card.hasBehaviour(DoesNotUnTapOnUpkeep.instance())) {
					return identifier;
				}
				break;
			case DOUBLE_STRIKE:
				if (card.hasBehaviour(DoubleStrike.instance())) {
					return identifier;
				}
				break;
			case FIRST_STRIKE:
				if (card.hasBehaviour(FirstStrike.instance())) {
					return identifier;
				}
				break;
			case FLYING:
				if (card.hasBehaviour(Flying.instance())) {
					return identifier;
				}
				break;
			case HASTE:
				if (card.hasBehaviour(Haste.instance())) {
					return identifier;
				}
				break;
			case HEXPROOF:
				if (card.hasBehaviour(Hexproof.instance())) {
					return identifier;
				}
				break;
			case INTIMIDATE:
				if (card.hasBehaviour(Intimidate.instance())) {
					return identifier;
				}
				break;
			case ISLANDWALK:
				if (card.hasBehaviour(Islandwalk.instance())) {
					return identifier;
				}
				break;
			case LIFE_LINK:
				if (card.hasBehaviour(LifeLink.instance())) {
					return identifier;
				}
				break;
			case MORBID:
				if (card.hasBehaviour(Morbid.instance())) {
					return identifier;
				}
				break;
			case REACH:
				if (card.hasBehaviour(Reach.instance())) {
					return identifier;
				}
			case SUMMONING_SICKENSS:
				if (card.hasBehaviour(SummoningSickness.instance())) {
					return identifier;
				}
				break;
			case TAPPED:
				if (card.hasBehaviour(Tapped.instance())) {
					return identifier;
				}
				break;
			case TRAMPLE:
				if (card.hasBehaviour(Trample.instance())) {
					return identifier;
				}
			case UNBLOCKABLE:
				if (card.hasBehaviour(Unblockable.instance())) {
					return identifier;
				}
				break;
			case NOT_SUMMONING_SICKENSS:
				if (!card.hasBehaviour(SummoningSickness.instance())) {
					return identifier;
				}
				break;
			case NOT_TAPPED:
				if (!card.hasBehaviour(Tapped.instance())) {
					return identifier;
				}
				break;
			case NOT_DEFENDER:
				if (!card.hasBehaviour(Defender.instance())) {
					return identifier;
				}
				break;
			}
		}
		return -1;
	}

}
